* keyboard.c (make_lispy_event): Added detection of double-click
authorJim Blandy <jimb@redhat.com>
Tue, 22 Jun 1993 02:06:54 +0000 (02:06 +0000)
committerJim Blandy <jimb@redhat.com>
Tue, 22 Jun 1993 02:06:54 +0000 (02:06 +0000)
and triple-click events.
(parse_modifiers_uncached, apply_modifiers_uncached): Same.
(read_key_sequence): Coerce double-clicks to clicks, and triple-clicks
to double-clicks or clicks, by analogy with drag events.
(double_click_time): Added variable.
* termhooks.h: Added multi-click event modifier bits.

src/keyboard.c
src/termhooks.h

index 49d27b0dcdcc021819fe0d132db0b1cd763b9fe0..6a18aed16f99bad67570fdd069e85ce647825977 100644 (file)
@@ -2143,6 +2143,22 @@ Lisp_Object *scroll_bar_parts[] = {
 
 static Lisp_Object button_down_location;
 
+/* Information about the most recent up-going button event:  Which
+   button, what location, and what time. */
+
+static int button_up_button;
+static int button_up_x;
+static int button_up_y;
+static unsigned long button_up_time;
+
+/* The minimum time between clicks to make a double-click. */
+
+int double_click_time;
+
+/* The number of clicks in this multiple-click. */
+
+int double_click_count;
+
 /* Given a struct input_event, build the lisp event which represents
    it.  If EVENT is 0, build a mouse movement event from the mouse
    movement buffer, which should have a movement event in it.
@@ -2176,12 +2192,14 @@ make_lispy_event (event)
        c |= (event->modifiers
              & (meta_modifier | alt_modifier
                 | hyper_modifier | super_modifier));
+       button_up_time = 0;
        return c;
       }
 
       /* A function key.  The symbol may need to have modifier prefixes
         tacked onto it.  */
     case non_ascii_keystroke:
+      button_up_time = 0;
       return modify_event_symbol (XFASTINT (event->code), event->modifiers,
                                  Qfunction_key,
                                  lispy_function_keys, &func_key_syms,
@@ -2316,10 +2334,36 @@ make_lispy_event (event)
                   pair.  */
                Lisp_Object down = Fnth (make_number (2), start_pos);
 
-               event->modifiers |= ((EQ (event->x, XCONS (down)->car)
-                                     && EQ (event->y, XCONS (down)->cdr))
-                                    ? click_modifier
-                                    : drag_modifier);
+               if (EQ (event->x, XCONS (down)->car)
+                   && EQ (event->y, XCONS (down)->cdr))
+                 {
+                   if (button == button_up_button
+                       && XINT (event->x) == button_up_x
+                       && XINT (event->y) == button_up_y
+                       && button_up_time != 0
+                       && ((int)(event->timestamp - button_up_time)
+                           < double_click_time))
+                     {
+                       double_click_count++;
+                       event->modifiers |= ((double_click_count > 2)
+                                            ? triple_modifier
+                                            : double_modifier);
+                     }
+                   else
+                     {
+                       double_click_count = 1;
+                       event->modifiers |= click_modifier;
+                     }
+                   button_up_button = button;
+                   button_up_x = XINT (event->x);
+                   button_up_y = XINT (event->y);
+                   button_up_time = event->timestamp;
+                 }
+               else
+                 {
+                   button_up_time = 0;
+                   event->modifiers |= drag_modifier;
+                 }
              }
          }
        else
@@ -2342,6 +2386,11 @@ make_lispy_event (event)
                          Fcons (start_pos,
                                 Fcons (position,
                                        Qnil)));
+         else if (event->modifiers & (double_modifier | triple_modifier))
+           return Fcons (head,
+                         Fcons (position,
+                                Fcons (make_number (double_click_count),
+                                       Qnil)));
          else
            return Fcons (head,
                          Fcons (position,
@@ -2498,6 +2547,24 @@ parse_modifiers_uncached (symbol, modifier_end)
            modifiers |= down_modifier;
            i += 5;
          }
+       else if (i + 7 <= name->size
+                && ! strncmp (name->data + i, "double-", 7))
+         {
+           modifiers |= double_modifier;
+           i += 7;
+         }
+       else
+         goto no_more_modifiers;
+       break;
+
+      case 't':
+       if (i + 7 > name->size)
+         goto no_more_modifiers;
+       if (! strncmp (name->data + i, "triple-", 7))
+         {
+           modifiers |= triple_modifier;
+           i += 7;
+         }
        else
          goto no_more_modifiers;
        break;
@@ -2510,7 +2577,8 @@ parse_modifiers_uncached (symbol, modifier_end)
  no_more_modifiers:
 
   /* Should we include the `click' modifier?  */
-  if (! (modifiers & (down_modifier | drag_modifier))
+  if (! (modifiers & (down_modifier | drag_modifier
+                     | double_modifier | triple_modifier))
       && i + 7 == name->size
       && strncmp (name->data + i, "mouse-", 6) == 0
       && ('0' <= name->data[i + 6] && name->data[i + 6] <= '9'))
@@ -2536,7 +2604,7 @@ apply_modifiers_uncached (modifiers, base, base_len)
      to use Fintern, which expects a genuine Lisp_String, and keeps a
      reference to it.  */
   char *new_mods =
-    (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-"));
+    (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-"));
   int mod_len;
 
   {
@@ -2555,6 +2623,8 @@ apply_modifiers_uncached (modifiers, base, base_len)
     if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; }
     if (modifiers & down_modifier)  { strcpy (p, "down-");  p += 5; }
     if (modifiers & drag_modifier)  { strcpy (p, "drag-");  p += 5; }
+    if (modifiers & double_modifier)  { strcpy (p, "double-");  p += 7; }
+    if (modifiers & triple_modifier)  { strcpy (p, "triple-");  p += 7; }
     /* The click modifier is denoted by the absence of other modifiers.  */
 
     *p = '\0';
@@ -2575,7 +2645,7 @@ apply_modifiers_uncached (modifiers, base, base_len)
 
 static char *modifier_names[] =
 {
-  "up", "down", "drag", "click", 0, 0, 0, 0,
+  "up", "down", "drag", "click", "double", "triple", 0, 0,
   0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, "alt", "super", "hyper", "shift", "control", "meta"
 };
@@ -3525,8 +3595,10 @@ follow_key (key, nmaps, current, defs, next)
    function key's sequence.  If so, we try to read the whole function
    key, and substitute its symbolic name into the key sequence.
 
-   We ignore unbound `down-' mouse clicks.  We turn unbound `drag-'
-   events into similar click events, if that would make them bound.
+   We ignore unbound `down-' mouse clicks.  We turn unbound `drag-' and
+   `double-' events into similar click events, if that would make them
+   bound.  We try to turn `triple-' events first into `double-' events,
+   then into clicks.
 
    If we get a mouse click in a mode line, vertical divider, or other
    non-text area, we treat the click as if it were prefixed by the
@@ -3947,29 +4019,41 @@ read_key_sequence (keybuf, bufsize, prompt)
 
              /* We turn unbound `drag-' events into `click-'
                 events, if the click would be bound.  */
-             else if (modifiers & drag_modifier)
+             else if (modifiers & (drag_modifier | double_modifier
+                                   | triple_modifier))
                {
-                 Lisp_Object new_head =
-                   apply_modifiers (modifiers & ~drag_modifier,
-                                    XCONS (breakdown)->car);
-                 Lisp_Object new_click =
-                   Fcons (new_head, Fcons (EVENT_START (key), Qnil));
-
-                 /* Look for a binding for this new key.  follow_key
-                    promises that it didn't munge submaps the
-                    last time we called it, since key was unbound.  */
-                 first_binding =
-                   (follow_key (new_click,
-                                nmaps   - local_first_binding,
-                                submaps + local_first_binding,
-                                defs    + local_first_binding,
-                                submaps + local_first_binding)
-                    + local_first_binding);
-
-                 /* If that click is bound, go for it.  */
-                 if (first_binding < nmaps)
-                   key = new_click;
-                 /* Otherwise, we'll leave key set to the drag event.  */
+                 while (modifiers & (drag_modifier | double_modifier
+                                     | triple_modifier))
+                   {
+                     Lisp_Object new_head, new_click;
+                     if (modifiers & triple_modifier)
+                       modifiers ^= (double_modifier | triple_modifier);
+                     else
+                       modifiers &= ~(drag_modifier | double_modifier);
+                     new_head =
+                       apply_modifiers (modifiers, XCONS (breakdown)->car);
+                     new_click =
+                       Fcons (new_head, Fcons (EVENT_START (key), Qnil));
+
+                     /* Look for a binding for this new key.  follow_key
+                        promises that it didn't munge submaps the
+                        last time we called it, since key was unbound.  */
+                     first_binding =
+                       (follow_key (new_click,
+                                    nmaps   - local_first_binding,
+                                    submaps + local_first_binding,
+                                    defs    + local_first_binding,
+                                    submaps + local_first_binding)
+                        + local_first_binding);
+
+                     /* If that click is bound, go for it.  */
+                     if (first_binding < nmaps)
+                       {
+                         key = new_click;
+                         break;
+                       }
+                     /* Otherwise, we'll leave key set to the drag event.  */
+                   }
                }
            }
        }
@@ -4093,10 +4177,10 @@ of the selected window as normal.\n\
 \n\
 `read-key-sequence' drops unbound button-down events, since you normally\n\
 only care about the click or drag events which follow them.  If a drag\n\
-event is unbound, but the corresponding click event would be bound,\n\
-`read-key-sequence' turns the drag event into a click event at the\n\
+or multi-click event is unbound, but the corresponding click event would\n\
+be bound, `read-key-sequence' turns the event into a click event at the\n\
 drag's starting position.  This means that you don't have to distinguish\n\
-between click and drag events unless you want to.\n\
+between click and drag, double, or triple events unless you want to.\n\
 \n\
 `read-key-sequence' prefixes mouse events on mode lines, the vertical\n\
 lines separating windows, and scroll bars with imaginary keys\n\
@@ -4979,6 +5063,13 @@ Polling is needed only when using X windows and SIGIO does not work.\n\
 Polling is automatically disabled in all other cases.");
   polling_period = 2;
   
+  DEFVAR_INT ("double-click-time", &double_click_time,
+    "*Maximum time between mouse clicks to make a double-click.\n\
+Measured in milliseconds.  Zero means disable double-click recognition;\n\
+a large number means double-clicks have no time limit and are detected\n\
+by position only.");
+  double_click_time = 500;
+
   DEFVAR_INT ("num-input-keys", &num_input_keys,
     "*Number of complete keys read from the keyboard so far.");
   num_input_keys = 0;
index a410038f5f6a7e61c1a8afbca67cb11aeae0cd0a..53d48f254e6c74fbb0cb4b249983e78d6cc1b3f1 100644 (file)
@@ -286,10 +286,11 @@ struct input_event {
    is a mouse click lacking the click and drag modifiers.
 
    The window-system independent code turns all up_modifier events
-   bits into either drag_modifier or click_modifier events.  The
-   click_modifier has no written representation in the names of the
-   symbols used as event heads, but it does appear in the
-   Qevent_symbol_components property of the event heads.  */
+   bits into drag_modifier, click_modifier, double_modifier, or
+   triple_modifier events.  The click_modifier has no written
+   representation in the names of the symbols used as event heads,
+   but it does appear in the Qevent_symbol_components property of the
+   event heads.  */
 enum {
   up_modifier  =   1,          /* Only used on mouse buttons - always
                                   turned into a click or a drag modifier
@@ -299,6 +300,8 @@ enum {
                                   queue; it's only used internally by
                                   the window-system-independent code.  */
   click_modifier=   8,         /* See drag_modifier.  */
+  double_modifier= 16,          /* See drag_modifier.  */
+  triple_modifier= 32,          /* See drag_modifier.  */
 
   /* The next four modifier bits are used also in keyboard events at
      the Lisp level.